package plp.funcoo.io;

import plp.funcoo.environment.compilation.CompilationContext;
import plp.funcoo.environment.compilation.CompilationEnvironment;
import plp.funcoo.environment.compilation.Environment;
import plp.funcoo.environment.execution.ExecutionContext;
import plp.funcoo.environment.execution.ExecutionEnvironment;
import plp.funcoo.exceptions.ClassAlreadyDeclared;
import plp.funcoo.exceptions.ClassNotDeclared;
import plp.funcoo.exceptions.MethodAlreadDeclared;
import plp.funcoo.exceptions.MethodNotDeclared;
import plp.funcoo.exceptions.VarAlreadyDeclared;
import plp.funcoo.exceptions.VarNotDeclared;
import plp.funcoo.expressions.Expression;
import plp.funcoo.expressions.Identifier;
import plp.funcoo.types.PrimitiveType;
import plp.funcoo.util.Type;
import plp.funcoo.value.Value;

public class Read implements Expression{

	private Identifier id;
	
	public Read(Identifier id)
	{
		this.id = id;
	}

	@Override
	public ExecutionEnvironment evaluate(ExecutionEnvironment envi) throws VarNotDeclared, MethodNotDeclared, VarAlreadyDeclared, MethodAlreadDeclared {
		
		Value aux = ((ExecutionContext)envi).getValueInput().getNext();
		
		envi.changeValue(this.id, aux);
		((ExecutionContext)envi).cleanExpression();
		
		return envi;
	}

	@Override
	public boolean typeCheck(CompilationEnvironment envi)
			throws VarAlreadyDeclared, VarNotDeclared, ClassAlreadyDeclared,
			ClassNotDeclared {
		if(this.id.typeCheck(envi))
		{
			Expression exp =((CompilationContext)envi).getInput().getLast();
			if(exp != null)
				return exp.getType(envi).equals(this.id.getType(envi));
			else
				throw new VarNotDeclared(this.id);
		}
		else
			return false;
	}

	@Override
	public Type getType(Environment envi) throws VarNotDeclared,
			ClassNotDeclared {
		return PrimitiveType.Type_VOID;
	}

	@Override
	public Expression makeCopy() {
		return new Read((Identifier)id.makeCopy());
	}
}
